﻿using System;
using System.Collections.Generic;
using System.Text;

namespace NCommet.Core
{
    /// <summary>
    /// RelItemCollection is a collection of RelItem objects.
    /// </summary>
    public class RelItemCollection : IList<RelItem>
    {
        private Item owner;

        internal RelItemCollection(Item owner)
        {
            this.owner = owner;
        }

        private IList<RelItem> store { get { return owner.internalRelatives; } }

        /// <summary>
        /// Creates a new RelItem and adds it to the RelItem collection. See also <see cref="RelItem"/>.
        /// </summary>
        /// <param name="relative">The object of the relation.</param>
        /// <param name="relationType">The relation of the two items.</param>        
        public void Add(Item relative, String relationType)
        {
            store.Add(new RelItem(owner, relative, relationType));
        }

        /// <summary>
        /// Removes a RelItem from the RelItem collection. See also <see cref="RelItem"/>.
        /// </summary>
        /// <param name="relative">The object of the relation.</param>
        /// <param name="relationType">The relation of the two items.</param>
        /// <exception cref="InvalidOperationException">
        /// If the item is not related to any other item.
        /// </exception>
        public void Delete(Item relative, String relationType)
        {
            RelItem relItem = new RelItem(owner, relative, relationType);
            if (store.Contains(relItem))
                store.Remove(relItem);
            else
                throw new InvalidOperationException("Item is not related");
        }

        /// <summary>
        /// Checks if the owner of this relItem (subject) is related to another item (object) with the specified relation./>.
        /// </summary>
        /// <param name="relative">The object of the relation.</param>
        /// <param name="relationType">The relation of the two items.</param>
        /// <returns>True, if the items are related.</returns>        
        public bool IsRelated(Item relative, String relationType)
        {
            RelItem relItem = new RelItem(owner, relative, relationType);
            return store.Contains(relItem);
        }

        /// <summary>
        /// Checks if the owner of this relItem (subject) is related to another item (object) with the any relation./>.
        /// </summary>
        /// <param name="relative">The object of the relation.</param>        
        /// <returns>True, if the items are related with any relation.</returns>
        public bool IsRelated(Item relative)
        {
            foreach (RelItem relItem in store)
                if (relItem.Relative == relative)
                    return true;
            return false;
        }

        #region IList<RelItem> Members

        /// <summary>
        /// Returns the index of the relItem in the relItem collection.
        /// </summary>
        /// <param name="item">The item in the relItem collection.</param>
        /// <returns>The index of the relItem.</returns>
        public int IndexOf(RelItem item)
        {
            return store.IndexOf(item);
        }

        /// <summary>
        /// Inserts a relItem to the relItem collection at the specified index.        
        /// </summary>        
        /// <param name="index">The index in the relItem collection, where this relItem is inserted.</param>
        /// <param name="item">The relItem to be inserted in the relItem collection.</param>
        /// <exception cref="ArgumentException">
        /// If the owner this collection (subject) is not the same as the owner of <paramref name="item"/> (object).
        /// </exception>        
        public void Insert(int index, RelItem item)
        {
            if (item.Owner != this.owner)
                throw new ArgumentException("Owner of item is not the same as owner of RelItemCollection", "item");
            store.Insert(index, item);
        }

        /// <summary>
        /// Removes the relItem at the specified index.        
        /// </summary>
        /// <param name="index">The index of the relItem that is going to be removed from the collection.</param>        
        public void RemoveAt(int index)
        {
            store.RemoveAt(index);
        }

        /// <summary>
        /// Returns the relItem at the specified index in the collection.
        /// </summary>
        /// <remarks>
        /// Setting is not allowed, the setter property throws <see cref="NotSupportedException" />.
        /// </remarks>
        /// <param name="index">The index of the item.</param>
        /// <returns>The item at the specified index.</returns>
        /// <exception cref="NotSupportedException">
        /// If a an attempt to set the relItem at a specified index is made.
        /// </exception>
        public RelItem this[int index]
        {
            get
            {
                return store[index];
            }
            set
            {
                throw new NotSupportedException("The method or operation is not implemented.");
            }
        }

        #endregion

        #region ICollection<RelItem> Members

        /// <summary>
        /// Adds the specified relItem to the relItem collection.
        /// </summary>
        /// <param name="item">The relItem to be added in the relItem collection.</param>
        /// <exception cref="ArgumentException">
        /// If the owner this collection (subject) is not the same as the owner of <paramref name="item"/> (object).
        /// </exception>        
        public void Add(RelItem item)
        {
            if (item.Owner != this.owner)
                throw new ArgumentException("Owner of item was not same as owner of RelItemCollection");
            store.Add(item);
        }

        /// <summary>
        /// Removes relItem from the relItem collection.
        /// </summary>
        public void Clear()
        {
            store.Clear();
        }

        /// <summary>
        /// Determines whether the collection contains the specified relItem.
        /// </summary>
        /// <param name="item">The relItem that is checked.</param>
        /// <returns>True, if the relItem exists in the collection.</returns>
        public bool Contains(RelItem item)
        {
            return store.Contains(item);
        }

        /// <summary>
        /// Copies the relItems to the specified array, starting at the given index.
        /// </summary>
        /// <param name="array">The array where the relItems are copied.</param>
        /// <param name="arrayIndex">The starting index.</param>
        public void CopyTo(RelItem[] array, int arrayIndex)
        {
            store.CopyTo(array, arrayIndex);
        }

        /// <summary>
        /// Gets the number of elements contained in the collection.
        /// </summary>
        public int Count
        {
            get { return store.Count; }
        }

        /// <summary>
        /// Specifies whether this collection is readonly or not. The <c>RelItemCollection</c> is never readonly.
        /// </summary>
        public bool IsReadOnly
        {
            get { return false; }
        }

        /// <summary>
        /// Removes the specified relItem from the collection.
        /// </summary>
        /// <param name="item">The item to remove.</param>
        /// <returns>True, if the relItem is removed successfully.</returns>        
        public bool Remove(RelItem item)
        {
            return store.Remove(item);
        }

        #endregion

        #region IEnumerable<RelItem> Members

        /// <summary>
        /// Returns an enumerator that iterates through the collection.
        /// </summary>
        /// <returns>An enumerator of <see cref="NCommet.Core.RelItem">RelItems</see></returns>
        public IEnumerator<RelItem> GetEnumerator()
        {
            return store.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        /// <summary>
        /// Returns an enumerator that iterates through the collection.
        /// </summary>
        /// <returns>An enumerator to iterate through the collection.</returns>
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return store.GetEnumerator();
        }

        #endregion
    }
}
